﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using Gronia.WPF.Classes;

namespace Gronia.WPF.Controls
{
    public partial class HyperPanel : Panel
    {
        static HyperPanel()
        {
            OrientationProperty.OverrideMetadata(typeof(HyperPanel), new FrameworkPropertyMetadata(Orientation.Horizontal, FrameworkPropertyMetadataOptions.AffectsMeasure, new PropertyChangedCallback(OnOrientationPropertyChanged)));
        }

        public HyperPanel()
        {
            this.MouseMove += HyperPanel_MouseMove;
            SizeChanged += delegate
            {
                InvalidateMeasure(); 
            };
            Loaded += delegate
            {
                if (Background == null)
                {
                    Background = Brushes.Transparent;
                }
            };
        }

        private void HyperPanel_MouseMove(object sender, MouseEventArgs e)
        {
            if (EffectType == HyperPanelEffectType.Mouse)
            {
                Point p = Mouse.GetPosition(this);
                double o = Orientation == Orientation.Horizontal ? ActualWidth : ActualHeight;
                if (o == 0)
                {
                    return;
                }
                double center = (Orientation == Orientation.Horizontal ? p.X : p.Y) / o;
                Center = center;
            }
        }

        private static void OnOrientationPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            HyperPanel panel = (HyperPanel)sender;
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            Size stackDesiredSize = new Size();
            UIElementCollection children = InternalChildren;
            Size layoutSlotSize = availableSize;
            bool isHorizontal = (Orientation == Orientation.Horizontal);
            if (isHorizontal)
            {
                layoutSlotSize.Width = Double.PositiveInfinity;
            }
            else
            {
                layoutSlotSize.Height = Double.PositiveInfinity;
            }
            for (int i = 0, count = children.Count; i < count; ++i)
            {
                FrameworkElement child = (FrameworkElement)children[i];
                if (child == null) { continue; }

                if (GetTempOpacity(child).HasValue)
                {
                    child.Opacity = GetTempOpacity(child).Value;
                }
                else
                {
                    SetTempOpacity(child, child.Opacity);
                }

                child.Measure(layoutSlotSize);
                Size childDesiredSize = child.DesiredSize;
                if (isHorizontal)
                {
                    stackDesiredSize.Width += childDesiredSize.Width;
                    stackDesiredSize.Height = Math.Max(stackDesiredSize.Height, childDesiredSize.Height);
                }
                else
                {
                    stackDesiredSize.Width = Math.Max(stackDesiredSize.Width, childDesiredSize.Width);
                    stackDesiredSize.Height += childDesiredSize.Height;
                }

                double Distr = ((isHorizontal ? availableSize.Width : availableSize.Height) / 4) * Distribution;
                double center = (isHorizontal ? availableSize.Width : availableSize.Height) * Center;
                double cds = isHorizontal ? childDesiredSize.Width : childDesiredSize.Height;
                double sds = isHorizontal ? availableSize.Width : availableSize.Height;

                Point ChildPosition = child.TransformToVisual(this).Transform(new Point(0, 0));
                double CCenter = isHorizontal ? ChildPosition.X : ChildPosition.Y;
                if ((CCenter - Distr) > center || (CCenter + cds + Distr) < center)
                {
                    double Dist = 0;
                    if (CCenter > center)
                    {
                        Dist = (CCenter - center) / sds;
                    }
                    else if ((CCenter + cds) < center)
                    {
                        Dist = (center - CCenter + cds) / sds;
                    }
                    else
                    {
                        Dist = 0;
                    }

                    double ScaleFactor = MathUtilities.Clamp((1 - Dist), MinimumScale, 1);
                    ScaleTransform nscale = new ScaleTransform(ScaleFactor, ScaleFactor);
                    child.LayoutTransform = nscale;

                    if (ApplyOpacity)
                    {
                        child.Opacity = ScaleFactor;
                    }
                    else if (GetTempOpacity(child).HasValue)
                    {
                        child.Opacity = GetTempOpacity(child).Value;
                    }
                }
                else
                {
                    ScaleTransform scale = new ScaleTransform(1, 1);
                    child.LayoutTransform = scale;
                }
            }
            return stackDesiredSize;
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            UIElementCollection children = InternalChildren;
            bool isHorizontal = (Orientation == Orientation.Horizontal);
            Rect childRect = new Rect(finalSize);
            double previousChildSize = 0;
            for (int i = 0, count = children.Count; i < count; ++i)
            {
                UIElement child = (UIElement)children[i];
                if (child == null) { continue; }
                if (isHorizontal)
                {
                    childRect.X += previousChildSize;
                    previousChildSize = child.DesiredSize.Width;
                    childRect.Width = previousChildSize;
                    childRect.Height = Math.Max(finalSize.Height, child.DesiredSize.Height);
                }
                else
                {
                    childRect.Y += previousChildSize;
                    previousChildSize = child.DesiredSize.Height;
                    childRect.Height = previousChildSize;
                    childRect.Width = Math.Max(finalSize.Width, child.DesiredSize.Width);
                }
                child.Arrange(childRect);
            }
            return finalSize;
        }
    }
}